home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / demo / nfs-demo.zip / PCNFSD.C < prev    next >
C/C++ Source or Header  |  1994-08-29  |  19KB  |  700 lines

  1. #ifdef sccs
  2. static char     sccsid[] = "@(#)pcnfsd.c    1.4";
  3.  
  4. #endif
  5.  
  6. /*
  7.  * Copyright (c) 1986 by Sun Microsystems, Inc. 
  8.  */
  9.  
  10. /*
  11.  * pcnfsd.c 
  12.  *
  13.  * pcnfsd is intended to remedy the lack of certain critical generic network
  14.  * services by providing an simple, customizable set of RPC-based
  15.  * mechanisms. For this reason, Sun Microsystems Inc. is distributing it
  16.  * in source form as part of the PC-NFS release. 
  17.  *
  18.  * Background: The first NFS networks were composed of systems running
  19.  * derivatives of the 4.2BSD release of Unix (Sun's, VAXes, Goulds and
  20.  * Pyramids). The immediate utility of the resulting networks was derived
  21.  * not only from NFS but also from the availability of a number of TCP/IP
  22.  * based network services derived from 4.2BSD. Furthermore the thorny
  23.  * question of network-wide user authentication, while remaining a
  24.  * security hole, was solved at least in terms of a convenient usage model
  25.  * by the Yellow Pages distributed data base facility, which allows
  26.  * multiple Unix systems to refer to common password and group files. 
  27.  *
  28.  * The PC-NFS Dilemma: When Sun Microsystems Inc. ported NFS to PC's, two
  29.  * things became apparent. First, the memory constraints of the typical PC
  30.  * meant that it would be impossible to incorporate the pervasive TCP/IP
  31.  * based service suite in a resident fashion. Indeed it was not at all
  32.  * clear that the 4.2BSD services would prove sufficient: with the advent
  33.  * of Unix System V and (experimental) VAX-VMS NFS implementations, we had
  34.  * to consider the existence of networks with no BSD-derived Unix hosts.
  35.  * The two key types of functionality we needed to provide were remote
  36.  * login and print spooling. The second critical issue  was that of user
  37.  * authentication. Traditional time-sharing systems such as Unix and VMS
  38.  * have well- established user authentication mechanisms based upon user
  39.  * id's and passwords: by defining appropriate mappings, these could
  40.  * suffice for network-wide authentication provided that appropriate
  41.  * administrative procedures were enforced. The PC, however, is typically
  42.  * a single-user system, and the standard DOS operating environment
  43.  * provides no user authentication mechanisms. While this is acceptable
  44.  * within a single PC, it causes problems when attempting to connect to a
  45.  * heterogeneous network of systems in which access control, file space
  46.  * allocation, and print job accounting and routing may all be based upon
  47.  * a user's identity. The initial (and default) approach is to use the
  48.  * pseudo-identity 'nobody' defined as part of NFS to handle problems such
  49.  * as this. However, taking ease of use into consideration, it became
  50.  * necessary to provide a mechanism for establishing a user's identity. 
  51.  *
  52.  * Initially we felt that we needed to implement two types of functionality:
  53.  * user authentication and print spooling. (Remote login is addressed by
  54.  * the Telnet module.) Since no network services were defined within the
  55.  * NFS architecture to support these, it was decided to implement them in
  56.  * a fairly portable fashion using Sun's Remote Procedure Call protocol.
  57.  * Since these mechanisms will need to be re-implemented ion a variety of
  58.  * software environments, we have tried to define a very general model. 
  59.  *
  60.  * Authentication: NFS adopts the Unix model of using a pair of integers
  61.  * (uid, gid) to define a user's identity. This happens to map tolerably
  62.  * well onto the VMS system. 'pcnfsd' implements a Remote Procedure which
  63.  * is required to map a username and password into a (uid, gid) pair.
  64.  * Since we cannot predict what mapping is to be performed, and since we
  65.  * do not wish to pass clear-text passwords over the net, both the
  66.  * username and the password are mildly scrambled using a simple XOR
  67.  * operation. The intent is not to be secure (the present NFS architecture
  68.  * is inherently insecure) but to defeat "browsers". 
  69.  *
  70.  * The authentication RPC will be invoked when the user enters the PC-NFS
  71.  * command: 
  72.  *
  73.  * NET NAME user [password|*] 
  74.  *
  75.  *
  76.  * Printing: The availability of NFS file operations simplifies the print
  77.  * spooling mechanisms. There are two services which 'pcnfsd' has to
  78.  * provide:
  79.  *   pr_init:    given the name of the client system, return the
  80.  * name of a directory which is exported via NFS and in which the client
  81.  * may create spool files.
  82.  *  pr_start: given a file name, a user name, the printer name, the client
  83.  * system name and an option string, initiate printing of the file
  84.  * on the named printer. The file name is relative to the directory
  85.  * returned by pr_init. pr_start is to be "idempotent": a request to print
  86.  * a file which is already being printed has no effect. 
  87.  *
  88.  * Intent: The first versions of these procedures are implementations for Sun
  89.  * 2.0/3.0 software, which will also run on VAX 4.2BSD systems. The intent
  90.  * is to build up a set of implementations for different architectures
  91.  * (Unix System V, VMS, etc.). Users are encouraged to submit their own
  92.  * variations for redistribution. If you need a particular variation which
  93.  * you don't see here, either code it yourself (and, hopefully, send it to
  94.  * us at Sun) or contact your Customer Support representative. 
  95.  */
  96.  
  97. #include <sys/types.h>
  98. #include <stdio.h>
  99. #include <rpc/rpc.h>
  100. #include <pwd.h>
  101. #include <sys/file.h>
  102. #include <signal.h>
  103. #include <sys/stat.h>
  104.  
  105. /*  #define DEBUG 1  */
  106.  
  107. #ifdef DEBUG
  108. int             buggit = 0;
  109.  
  110. #endif DEBUG
  111.  
  112. /*
  113.  * *************** RPC parameters ******************** 
  114.  */
  115. #define    PCNFSDPROG    (long)150001
  116. #define    PCNFSDVERS    (long)1
  117. #define    PCNFSD_AUTH    (long)1
  118. #define    PCNFSD_PR_INIT    (long)2
  119. #define    PCNFSD_PR_START    (long)3
  120.  
  121. /*
  122.  * ************* Other #define's ********************** 
  123.  */
  124. #ifndef MAXPATHLEN
  125. #define MAXPATHLEN 1024
  126. #endif
  127. #define    zchar        0x5b
  128.  
  129. /*
  130.  * *********** XDR structures, etc. ******************** 
  131.  */
  132. enum arstat {
  133.     AUTH_RES_OK, AUTH_RES_FAKE, AUTH_RES_FAIL
  134. };
  135. enum pirstat {
  136.     PI_RES_OK, PI_RES_NO_SUCH_PRINTER, PI_RES_FAIL
  137. };
  138. enum psrstat {
  139.     PS_RES_OK, PS_RES_ALREADY, PS_RES_NULL, PS_RES_NO_FILE,
  140.     PS_RES_FAIL
  141. };
  142.  
  143. struct auth_args {
  144.     char           *aa_ident;
  145.     char           *aa_password;
  146. };
  147.  
  148. struct auth_results {
  149.     enum arstat     ar_stat;
  150.     long            ar_uid;
  151.     long            ar_gid;
  152. };
  153.  
  154. struct pr_init_args {
  155.     char           *pia_client;
  156.     char           *pia_printername;
  157. };
  158.  
  159. struct pr_init_results {
  160.     enum pirstat    pir_stat;
  161.     char           *pir_spooldir;
  162. };
  163.  
  164. struct pr_start_args {
  165.     char           *psa_client;
  166.     char           *psa_printername;
  167.     char           *psa_username;
  168.     char           *psa_filename;    /* within the spooldir */
  169.     char           *psa_options;
  170. };
  171.  
  172. struct pr_start_results {
  173.     enum psrstat    psr_stat;
  174. };
  175.  
  176.  
  177. /*
  178.  * ****************** Misc. ************************ 
  179.  */
  180.  
  181. char           *authproc();
  182. char           *pr_start();
  183. char           *pr_init();
  184. struct stat     statbuf;
  185.  
  186. char            pathname[MAXPATHLEN];
  187. char            new_pathname[MAXPATHLEN];
  188. char            spoolname[MAXPATHLEN];
  189.  
  190. /*
  191.  * ************** Support procedures *********************** 
  192.  */
  193. scramble(s1, s2)
  194.     char           *s1;
  195.     char           *s2;
  196. {
  197.     while (*s1) {
  198.         *s2++ = (*s1 ^ zchar) & 0x7f;
  199.         s1++;
  200.     }
  201.     *s2 = 0;
  202. }
  203.  
  204. free_child()
  205. {
  206.     int             pid;
  207.     int             pstatus;
  208.  
  209.     pid = wait(&pstatus);    /* clear exit of child process */
  210.  
  211. #ifdef DEBUG
  212.     if (buggit || pstatus)
  213.         fprintf(stderr, "FREE_CHILD: process #%d exited with status 0X%x\r\n",
  214.             pid, pstatus);
  215. #endif DEBUG
  216.     return;
  217. }
  218.  
  219. /*
  220.  * *************** XDR procedures ***************** 
  221.  */
  222. bool_t
  223. xdr_auth_args(xdrs, aap)
  224.     XDR            *xdrs;
  225.     struct auth_args *aap;
  226. {
  227.     return (xdr_string(xdrs, &aap->aa_ident, 32) &&
  228.         xdr_string(xdrs, &aap->aa_password, 64));
  229. }
  230.  
  231. bool_t
  232. xdr_auth_results(xdrs, arp)
  233.     XDR            *xdrs;
  234.     struct auth_results *arp;
  235. {
  236.     return (xdr_enum(xdrs, &arp->ar_stat) &&
  237.         xdr_long(xdrs, &arp->ar_uid) &&
  238.         xdr_long(xdrs, &arp->ar_gid));
  239. }
  240.  
  241. bool_t
  242. xdr_pr_init_args(xdrs, aap)
  243.     XDR            *xdrs;
  244.     struct pr_init_args *aap;
  245. {
  246.     return (xdr_string(xdrs, &aap->pia_client, 64) &&
  247.         xdr_string(xdrs, &aap->pia_printername, 64));
  248. }
  249.  
  250. bool_t
  251. xdr_pr_init_results(xdrs, arp)
  252.     XDR            *xdrs;
  253.     struct pr_init_results *arp;
  254. {
  255.     return (xdr_enum(xdrs, &arp->pir_stat) &&
  256.         xdr_string(xdrs, &arp->pir_spooldir, 255));
  257. }
  258.  
  259. bool_t
  260. xdr_pr_start_args(xdrs, aap)
  261.     XDR            *xdrs;
  262.     struct pr_start_args *aap;
  263. {
  264.     return (xdr_string(xdrs, &aap->psa_client, 64) &&
  265.         xdr_string(xdrs, &aap->psa_printername, 64) &&
  266.         xdr_string(xdrs, &aap->psa_username, 64) &&
  267.         xdr_string(xdrs, &aap->psa_filename, 64) &&
  268.         xdr_string(xdrs, &aap->psa_options, 64));
  269. }
  270.  
  271. bool_t
  272. xdr_pr_start_results(xdrs, arp)
  273.     XDR            *xdrs;
  274.     struct pr_start_results *arp;
  275. {
  276.     return (xdr_enum(xdrs, &arp->psr_stat));
  277. }
  278.  
  279.  
  280.  
  281. /*
  282.  * ********************** main ********************* 
  283.  */
  284.  
  285. main(argc, argv)
  286.     int             argc;
  287.     char          **argv;
  288. {
  289.     int             f1, f2, f3;
  290.  
  291.         extern          xdr_string_array();
  292.  
  293.     if (fork() == 0) {
  294.         if (argc < 2)
  295.             strcpy(spoolname, "/usr/spool/lpd");
  296.         else
  297.             strcpy(spoolname, argv[1]);
  298. #ifdef DEBUG
  299.         if (argc > 2)
  300.             buggit++;
  301. #endif DEBUG
  302.  
  303.         if (stat(spoolname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
  304.             fprintf(stderr,
  305.                 "pcnfsd: invalid spool directory %s\r\n", spoolname);
  306.             exit(1);
  307.         }
  308.  
  309. /*  Comment out for now
  310.  
  311.         if ((f1 = open("/dev/null", O_RDONLY)) == -1) {
  312.             fprintf(stderr, "pcnfsd: couldn't open /dev/null\r\n");
  313.             exit(1);
  314.         }
  315.         if ((f2 = open("/dev/console", O_WRONLY)) == -1) {
  316.             fprintf(stderr, "pcnfsd: couldn't open /dev/console\r\n");
  317.             exit(1);
  318.         }
  319.         if ((f3 = open("/dev/console", O_WRONLY)) == -1) {
  320.             fprintf(stderr, "pcnfsd: couldn't open /dev/console\r\n");
  321.             exit(1);
  322.         }
  323.         dup2(f1, 0);
  324.         dup2(f2, 1);
  325.         dup2(f3, 2);
  326.         
  327. end of commented out stuff */
  328.  
  329.         registerrpc(PCNFSDPROG, PCNFSDVERS, PCNFSD_AUTH, authproc,
  330.             xdr_auth_args, xdr_auth_results);
  331.         registerrpc(PCNFSDPROG, PCNFSDVERS, PCNFSD_PR_INIT, pr_init,
  332.             xdr_pr_init_args, xdr_pr_init_results);
  333.         registerrpc(PCNFSDPROG, PCNFSDVERS, PCNFSD_PR_START, pr_start,
  334.             xdr_pr_start_args, xdr_pr_start_results);
  335.         svc_run();
  336.         fprintf(stderr, "pcnfsd: error: svc_run returned\r\n");
  337.         exit(1);
  338.     }
  339.     
  340. }
  341.  
  342. /*
  343.  * ******************* RPC procedures ************** 
  344.  */
  345.  
  346. char           *
  347. authproc(a)
  348.     struct auth_args *a;
  349. {
  350.     static struct auth_results r;
  351.     char            username[32];
  352.     char            password[64];
  353.     int             c1, c2;
  354.     struct passwd  *p;
  355.  
  356.     r.ar_stat = AUTH_RES_FAIL;    /* assume failure */
  357.     scramble(a->aa_ident, username);
  358.     scramble(a->aa_password, password);
  359.  
  360. #ifdef DEBUG
  361.     if (buggit)
  362.         fprintf(stderr, "AUTHPROC username=%s\r\n", username);
  363. #endif DEBUG
  364.  
  365.     p = getpwnam(username);
  366.     if (p == NULL)
  367.         return ((char *) &r);
  368.     c1 = strlen(password);
  369.     c2 = strlen(p->pw_passwd);
  370.     if ((c1 && !c2) || (c2 && !c1) ||
  371.         (strcmp(p->pw_passwd, crypt(password, p->pw_passwd)))) {
  372.         return ((char *) &r);
  373.     }
  374.     r.ar_stat = AUTH_RES_OK;
  375.     r.ar_uid = p->pw_uid;
  376.     r.ar_gid = p->pw_gid;
  377.     return ((char *) &r);
  378. }
  379.  
  380.  
  381. char           *
  382. pr_init(pi_arg)
  383.     struct pr_init_args *pi_arg;
  384. {
  385.     int             dir_mode = 0777;
  386.     static struct pr_init_results pi_res;
  387.  
  388.     /* get pathname of current directory and return to client */
  389.     strcpy(pathname, spoolname);    /* first the spool area */
  390.     strcat(pathname, "/");    /* append a slash */
  391.     strcat(pathname, pi_arg->pia_client);
  392.     /* now the host name */
  393.     mkdir(pathname);    /* ignore the return code */
  394.     if (stat(pathname, &statbuf) || !(statbuf.st_mode & S_IFDIR)) {
  395.         fprintf(stderr,
  396.             "pcnfsd: unable to create spool directory %s\r\n",
  397.             pathname);
  398.         pathname[0] = 0;/* null to tell client bad vibes */
  399.         pi_res.pir_stat = PI_RES_FAIL;
  400.     } else {
  401.         pi_res.pir_stat = PI_RES_OK;
  402.     }
  403.     pi_res.pir_spooldir = &pathname[0];
  404.     chmod(pathname, dir_mode);
  405.  
  406. #ifdef DEBUG
  407.     if (buggit)
  408.         fprintf(stderr, "PR_INIT pathname=%s\r\n", pathname);
  409. #endif DEBUG
  410.  
  411.     return ((char *) &pi_res);
  412. }
  413.  
  414. char           *
  415. pr_start(ps_arg)
  416.     struct pr_start_args *ps_arg;
  417. {
  418.     static struct pr_start_results ps_res;
  419.     int             pid;
  420.     int             free_child();
  421.     char            printer_opt[64];
  422.     char            username_opt[64];
  423.     char            clientname_opt[64];
  424.     struct passwd  *p;
  425.     long        rnum;
  426.     char        snum[20];
  427.     int        z;
  428.  
  429.     strcpy(printer_opt, "-P");
  430.     strcpy(username_opt, "-J");
  431.     strcpy(clientname_opt, "-C");
  432.  
  433.     signal(SIGCHLD, free_child);    /* when child terminates it sends */
  434.     /* a signal which we must get */
  435.     strcpy(pathname, spoolname);    /* build filename */
  436.     strcat(pathname, "/");
  437.     strcat(pathname, ps_arg->psa_client);    /* /spool/host */
  438.     strcat(pathname, "/");    /* /spool/host/ */
  439.     strcat(pathname, ps_arg->psa_filename);    /* /spool/host/file */
  440.  
  441. #ifdef DEBUG
  442.     if (buggit) {
  443.         fprintf(stderr, "PR_START pathname=%s\r\n", pathname);
  444.         fprintf(stderr, "PR_START username= %s\r\n", ps_arg->psa_username);
  445.         fprintf(stderr, "PR_START client= %s\r\n", ps_arg->psa_client);
  446.     }
  447. #endif DEBUG
  448.  
  449.     strcat(printer_opt, ps_arg->psa_printername);
  450.     /* make it (e.g.) -Plw     */
  451.     strcat(username_opt, ps_arg->psa_username);
  452.     /* make it (e.g.) -Jbilly     */
  453.     strcat(clientname_opt, ps_arg->psa_client);
  454.     /* make it (e.g.) -Cmypc     */
  455.  
  456.     if (stat(pathname, &statbuf)) {
  457.         /*
  458.          * We can't stat the file. Let's try appending '.spl' and
  459.          * see if it's already in progress. 
  460.          */
  461.  
  462. #ifdef DEBUG
  463.         if (buggit)
  464.             fprintf(stderr, "...can't stat it.\r\n");
  465. #endif DEBUG
  466.  
  467.         strcat(pathname, ".spl");
  468.         if (stat(pathname, &statbuf)) {
  469.             /*
  470.              * It really doesn't exist. 
  471.              */
  472.  
  473. #ifdef DEBUG
  474.             if (buggit)
  475.                 fprintf(stderr, "...PR_START returns PS_RES_NO_FILE\r\n");
  476. #endif DEBUG
  477.  
  478.             ps_res.psr_stat = PS_RES_NO_FILE;
  479.             return ((char *) &ps_res);
  480.         }
  481.         /*
  482.          * It is already on the way. 
  483.          */
  484.  
  485. #ifdef DEBUG
  486.         if (buggit)
  487.             fprintf(stderr, "...PR_START returns PS_RES_ALREADY\r\n");
  488. #endif DEBUG
  489.  
  490.         ps_res.psr_stat = PS_RES_ALREADY;
  491.         return ((char *) &ps_res);
  492.     }
  493.     if (statbuf.st_size == 0) {
  494.         /*
  495.          * Null file - don't print it, just kill it. 
  496.          */
  497.         unlink(pathname);
  498.  
  499. #ifdef DEBUG
  500.         if (buggit)
  501.             fprintf(stderr, "...PR_START returns PS_RES_NULL\r\n");
  502. #endif DEBUG
  503.  
  504.         ps_res.psr_stat = PS_RES_NULL;
  505.         return ((char *) &ps_res);
  506.     }
  507.     /*
  508.      * The file is real, has some data, and is not already going out.
  509.      * We rename it by appending '.spl' and exec "lpr" to do the
  510.      * actual work. 
  511.      */
  512.     strcpy(new_pathname, pathname);
  513.     strcat(new_pathname, ".spl");
  514.  
  515. #ifdef DEBUG
  516.     if (buggit)
  517.         fprintf(stderr, "...renaming %s -> %s\r\n", pathname, new_pathname);
  518. #endif DEBUG
  519.  
  520.     /*
  521.      * See if the new filename exists so as not to overwrite it.
  522.      */
  523.  
  524.  
  525.     for(z = 0; z <100; z++) {
  526.         if (!stat(new_pathname, &statbuf)){
  527.             strcpy(new_pathname, pathname);  /* rebuild a new name */
  528.             sprintf(snum,"%ld",random());        /* get some number */
  529.             strncat(new_pathname, snum, 3);
  530.             strcat(new_pathname, ".spl");        /* new spool file */
  531. #ifdef DEBUG
  532.             if (buggit)
  533.                 fprintf(stderr, "...created new spl file -> %s\r\n", new_pathname);
  534.  
  535. #endif DEBUG
  536.         } else
  537.             break;
  538.     }
  539.         
  540.  
  541.     if (rename(pathname, new_pathname)) {
  542.         /*
  543.          * CAVEAT: Microsoft changed rename for Microsoft C V3.0.
  544.          * Check this if porting to Xenix. 
  545.          */
  546.         /*
  547.          * Should never happen. 
  548.          */
  549.         fprintf(stderr, "pcnfsd: spool file rename (%s->%s) failed.\r\n",
  550.             pathname, new_pathname);
  551.         ps_res.psr_stat = PS_RES_FAIL;
  552.         return ((char *) &ps_res);
  553.     }
  554.     pid = fork();
  555.     if (pid == 0) {
  556. #ifdef DEBUG
  557.         if (buggit)
  558.             fprintf(stderr, "...print options =%s\r\n", ps_arg->psa_options);
  559. #endif DEBUG
  560.         
  561.         if (ps_arg->psa_options[1] == 'd') {
  562.             /*
  563.              * This is a Diablo print stream. Apply the ps630
  564.              * filter with the appropriate arguments. 
  565.              */
  566. #ifdef DEBUG
  567.             if (buggit)
  568.                 fprintf(stderr, "...run_ps630 invoked\r\n");
  569. #endif DEBUG
  570.             run_ps630(new_pathname, ps_arg->psa_options);
  571.         }
  572.         execlp("/usr/ucb/lpr",
  573.             "lpr",
  574.             "-s",
  575.             "-r",
  576.             printer_opt,
  577.             username_opt,
  578.             clientname_opt,
  579.             new_pathname,
  580.             0);
  581.         perror("pcnfsd: exec lpr failed");
  582.         exit(0);    /* end of child process */
  583.     } else if (pid == -1) {
  584.         perror("pcnfsd: fork failed");
  585.  
  586. #ifdef DEBUG
  587.         if (buggit)
  588.             fprintf(stderr, "...PR_START returns PS_RES_FAIL\r\n");
  589. #endif DEBUG
  590.  
  591.         ps_res.psr_stat = PS_RES_FAIL;
  592.         return ((char *) &ps_res);
  593.     } else {
  594.  
  595. #ifdef DEBUG
  596.         if (buggit)
  597.             fprintf(stderr, "...forked child #%d\r\n", pid);
  598. #endif DEBUG
  599.  
  600.  
  601. #ifdef DEBUG
  602.         if (buggit)
  603.             fprintf(stderr, "...PR_START returns PS_RES_OK\r\n");
  604. #endif DEBUG
  605.  
  606.         ps_res.psr_stat = PS_RES_OK;
  607.         return ((char *) &ps_res);
  608.     }
  609. }
  610.  
  611. char           *
  612. mapfont(f, i, b)
  613.     char            f;
  614.     char            i;
  615.     char            b;
  616. {
  617.     static char     fontname[64];
  618.  
  619.     fontname[0] = 0;    /* clear it out */
  620.  
  621.     switch (f) {
  622.     case 'c':
  623.         strcpy(fontname, "Courier");
  624.         break;
  625.     case 'h':
  626.         strcpy(fontname, "Helvetica");
  627.         break;
  628.     case 't':
  629.         strcpy(fontname, "Times");
  630.         break;
  631.     default:
  632.         strcpy(fontname, "Times-Roman");
  633.         goto exit;
  634.     }
  635.     if (i != 'o' && b != 'b') {    /* no bold or oblique */
  636.         if (f == 't')    /* special case Times */
  637.             strcat(fontname, "-Roman");
  638.         goto exit;
  639.     }
  640.     strcat(fontname, "-");
  641.     if (b == 'b')
  642.         strcat(fontname, "Bold");
  643.     if (i == 'o')        /* o-blique */
  644.         strcat(fontname, f == 't' ? "Italic" : "Oblique");
  645.  
  646. exit:    return (&fontname[0]);
  647. }
  648.  
  649. /*
  650.  * run_ps630 performs the Diablo 630 emulation filtering process. ps630 is
  651.  * currently broken in the Sun release: it will not accept point size or
  652.  * font changes. If your version is fixed, define the symbol
  653.  * PS630_IS_FIXED and rebuild pcnfsd. 
  654.  */
  655.  
  656.  
  657. run_ps630(file, options)
  658.     char           *file;
  659.     char           *options;
  660. {
  661.     char            tmpfile[256];
  662.     char            commbuf[256];
  663.     int             i;
  664.  
  665.     strcpy(tmpfile, file);
  666.     strcat(tmpfile, "X");    /* intermediate file name */
  667.  
  668. #ifdef PS630_IS_FIXED
  669.     sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
  670.         options[2], options[3], tmpfile);
  671.     strcat(commbuf, mapfont(options[4], options[5], options[6]));
  672.     strcat(commbuf, " -F ");
  673.     strcat(commbuf, mapfont(options[7], options[8], options[9]));
  674.     strcat(commbuf, "  ");
  675.     strcat(commbuf, file);
  676. #else PS630_IS_FIXED
  677.     /*
  678.      * The pitch and font features of ps630 appear to be broken at
  679.      * this time. If you think it's been fixed at your site, define
  680.      * the compile-time symbol `ps630_is_fixed'. 
  681.      */
  682.     sprintf(commbuf, "/usr/local/bin/ps630 -p %s %s", tmpfile, file);
  683. #endif PS630_IS_FIXED
  684.  
  685.  
  686.     if (i = system(commbuf)) {
  687.         /*
  688.          * Under (un)certain conditions, ps630 may return -1
  689.          * even if it worked. Hence the commenting out of this
  690.          * error report. 
  691.          */
  692.          /* fprintf(stderr, "\r\n\nrun_ps630 rc = %d\r\n", i) */ ;
  693.         /* exit(1); */
  694.     }
  695.     if (rename(tmpfile, file)) {
  696.         perror("run_ps630: rename");
  697.         exit(1);
  698.     }
  699. }
  700.